package org.elucid.chess.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Map.Entry;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;

import org.apache.log4j.Logger;
import org.elucid.chess.model.Board;
import org.elucid.chess.model.Game;
import org.elucid.chess.model.Move;
import org.elucid.chess.model.Piece;
import org.elucid.chess.model.Square;
import org.elucid.collections.BiMap;

/**
 * Basic (Test Harness) UI implementation for a Game
 * 
 * @author george
 * 
 */
@SuppressWarnings("serial")
public class MainFrame extends JFrame implements ActionListener {

	private static Logger log = Logger.getLogger(MainFrame.class);
	
	private static final Color BLACK_SQUARE_COLOR = Color.DARK_GRAY;
	private static final Color WHITE_SQUARE_COLOR = Color.LIGHT_GRAY;
	private static final int EAST_WIDTH = 150;
	private static final int WIDTH = 750;
	private static final int CENTER_HEIGHT = 600;
	private static final int HEIGHT = 600;


	private Game game = null;
	private Move move = null;

	// maintain a mapping between UI buttons and Game Board Squares
	private BiMap<Square, JButton> squareButtons = new BiMap<Square, JButton>();
	private Square fromSquare = null;
	private Square lastSquare = null;

	private JPanel centerPanel = new JPanel();
	private JPanel eastPanel = new JPanel();

	private boolean isPaused = false;
	private JButton btnPause = new JButton("Pause");
	private JCheckBox chkShowLegalMoves;
	private JCheckBox chkShowThreats;
	private JTextArea txtMoveList = new JTextArea();
	private JScrollPane moveListScroll = new JScrollPane(txtMoveList);

	/**
	 * 
	 * @param game
	 * @throws Exception
	 */
	public MainFrame(Game game) throws Exception {
		super();
		this.game = game;
		this.setTitle("Chess");

		centerPanel.setLayout(new GridLayout(Board.ROWS, Board.COLUMNS));
		centerPanel.setPreferredSize(new Dimension(CENTER_HEIGHT, HEIGHT));
		eastPanel.setPreferredSize(new Dimension(EAST_WIDTH, 100));

		chkShowLegalMoves = new JCheckBox("Show legal moves");
		eastPanel.add(chkShowLegalMoves);

		chkShowThreats = new JCheckBox("Show threats");
		chkShowThreats.setSelected(true);
		eastPanel.add(chkShowThreats);
		
		btnPause.addActionListener(this);
		eastPanel.add(btnPause);

		moveListScroll.setPreferredSize(new Dimension(150, 300));
		eastPanel.add(moveListScroll);

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add(centerPanel, BorderLayout.CENTER);
		getContentPane().add(eastPanel, BorderLayout.EAST);
		this.setSize(WIDTH, HEIGHT);
		setLocationRelativeTo(null); // center

		for (Square square : getGame().getBoard().getSquares()) {
			JButton button = new JButton();
			button.addActionListener(this);
			button.setContentAreaFilled(true);
			button.setOpaque(true);
			button.setVerticalTextPosition(SwingConstants.CENTER);
			button.setHorizontalTextPosition(SwingConstants.CENTER);
			button.setBackground(square.isWhite() ? WHITE_SQUARE_COLOR : BLACK_SQUARE_COLOR);
			button.setForeground(square.isWhite() ? WHITE_SQUARE_COLOR : BLACK_SQUARE_COLOR);
			button.setBorderPainted(true);
			centerPanel.add(button);
			squareButtons.put(square, button);
		}

		renderBoard();
	}

	Border blueBorder = new LineBorder(Color.BLUE, 2);
	Border cyanBorder = new LineBorder(Color.CYAN, 2);
	
	/**
	 * @throws Exception
	 * 
	 */
	private void renderBoard() throws Exception {

		for (Entry<Square, JButton> entry : squareButtons.entrySet()) {
			JButton button = entry.getValue();
			button.setBorder(null); // reset all borders
			Square square = entry.getKey();

			if( chkShowThreats.isSelected() && game.getThreatenedSquares().keySet().contains(square) )
			{
				button.setBorder(cyanBorder);
			}
			
			Piece pieceAtSquare = getGame().getPieceSquares().getKey(square);
			if (pieceAtSquare != null) {
				Image image = null;
				image = UiUtil.getScaledImage(UiUtil.createImageIcon(UiUtil.getPieceImageURL(pieceAtSquare)), 0.20);
				button.setIcon(new ImageIcon(image));

				if (lastSquare != null && square.equals(lastSquare)) {
					button.setBorder(blueBorder);
				}
			} else {
				button.setIcon(null);
			}
		}

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof JButton) {

			if (e.getSource().equals(btnPause)) {
				isPaused = !isPaused;
				log.info(String.format("Pause: %s", isPaused));
			} else {

				JButton fromButton = (JButton) e.getSource();
				Square square = squareButtons.getKey(fromButton);
				Piece piece = getGame().getPieceSquares().getKey(square);

				if (fromSquare == null) {
					if (piece != null) {
						log.debug(String.format("from square selected %s", square));
						Border redBorder = new LineBorder(Color.RED, 2);
						fromButton.setBorder(redBorder);
						fromButton.setBorderPainted(true);
						fromSquare = square;

						// paint legal to-squares with a Green border
						if (chkShowLegalMoves.isSelected()) {
							List<Move> legalMoves = piece.listLegalMoves(getGame(), false);
							for (Move move : legalMoves) {
								JButton toButton = squareButtons.get(move.getToSquare());
								Border border = new LineBorder(Color.GREEN, 2);
								toButton.setBorder(border);
								toButton.setBorderPainted(true);
							}
						}
					}
				} else {
					move = new Move(fromSquare, square);
//					if (this.getGame().doMove(move)) {
						lastSquare = square;
//						try {
//
//							// update Board UI
//							renderBoard();
//
//						} catch (Exception ex) {
//							ex.printStackTrace();
//						}
//					} else {
//						log.error("move failed");
//					}
//
//					squareButtons.get(fromSquare).setBorder(null);

				}
			}
		}
	}

	public Game getGame() {
		return game;
	}

	public void update(Move move) throws Exception {
		this.txtMoveList.setText( this.txtMoveList.getText()+ move.toString() + "\n");

		this.fromSquare = move.getFromSquare();
		this.lastSquare = move.getToSquare();
		this.renderBoard();
	}

	public boolean isPaused() {
		return isPaused;
	}

	public void setMove(Move move) {
		this.move = move;
	}

	public Move getMove() {
		return move;
	}

	public void setFromSquare(Square fromSquare) {
		this.fromSquare = fromSquare;
		
	}

	public void resetMoveUi() {
		squareButtons.get(fromSquare).setBorder(null);
		setFromSquare(null);
	}
}
